using IQIGame.Onigao.Framework;
using IQIGame.Onigao.Framework.Serialization;
using IQIGame.Onigao.Logic;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using UnityEditor;
using UnityEngine;

namespace IQIGame.Onigao.GamePlay.Editors
{
    public class BattleCommandBatch
    {
        private const string scriptsPath = "Assets/Scripts/GamePlay/Runtime/Module/Share/Battle/UpdateCommand/";

        private const string queueControllerPath = "Assets/Scripts/GamePlay/Runtime/Module/Battle/Controller/BattleRenderQueueController.Parse.cs";
        private static string tabStr = string.Empty.PadLeft(4, ' ');

        [MenuItem("GameEditor/SerializeCustomConfig/BattleCommand", false, 2)]
        public static void BatchScripts()
        {
#region Command

            {
                var baseType = typeof(BaseBattleCommand);
                Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
                var rList = new List<Type>();
                foreach (Assembly assembly in assemblies)
                {
                    Type[] types = assembly.GetTypes();

                    foreach (Type type in types)
                    {
                        if (type.IsSubclassOf(baseType))
                        {
                            rList.Add(type);
                        }
                    }
                }

                for (int i = 0; i < rList.Count; i++)
                {
                    var rType = rList[i];
                    bool bHasCustom = false;
                    var rSb = new StringBuilder();
                    rSb.AppendLine("using System.Collections.Generic;");
                    rSb.AppendLine("using IQIGame.Onigao.Framework.Serialization;");
                    rSb.AppendLine("using IQIGame.Onigao.GamePlay;");
                    rSb.AppendLine("using IQIGame.Onigao.Framework;");
                    rSb.AppendLine("");
                    rSb.AppendLine("namespace IQIGame.Onigao.Logic");
                    rSb.AppendLine("{");
                    rSb.AppendLine($"    public sealed partial class {rType.Name}");
                    rSb.AppendLine("    {");

#region Serialize

                    rSb.AppendLine("        public override void Serialize(SOutputStream _buf)");
                    rSb.AppendLine("        {");
                    rSb.AppendLine("            base.Serialize(_buf);");
                    var rFields = rType.GetFields();
                    // 这里对field排下序，把自定义结构都丢到最后
                    var rFieldList = new List<FieldInfo>(rFields);
                    rFieldList.Sort(FieldSort);
                    for (int j = 0; j < rFieldList.Count; j++)
                    {
                        var rField = rFieldList[j];
                        if (!AppendField(rField, ref rSb, true, out _))
                        {
                            Debug.LogWarning($"{rType} 生成序列化文件内容需要手动补充. [{rField} 类型：{rField.FieldType}");
                        }
                    }

                    rSb.AppendLine("            this.OnSerialize(_buf);");
                    rSb.AppendLine("        }");
                    rSb.AppendLine();

#endregion

#region DeSerialize

                    rSb.AppendLine("        public override void DeSerialize(SInputStream _buf)");
                    rSb.AppendLine("        {");
                    rSb.AppendLine("            base.DeSerialize(_buf);");
                    for (int j = 0; j < rFieldList.Count; j++)
                    {
                        var rField = rFieldList[j];
                        if (!AppendField(rField, ref rSb, false, out var b))
                        {
                            Debug.LogWarning($"{rType} 生成序列化文件内容需要手动补充. [{rField} 类型：{rField.FieldType}");
                        }
                        bHasCustom |= b;
                    }
                    rSb.AppendLine("            this.OnDeSerialize(_buf);");
                    rSb.AppendLine("        }");

#endregion

                    // Command对象随POD传输，不入对象池
                    // #region Free
                    //
                    // rSb.AppendLine("        public override void Free()");
                    // rSb.AppendLine("        {");
                    // rSb.AppendLine("            ClassPool.Put(this);");
                    // rSb.AppendLine("        }");
                    //
                    // #endregion

                    rSb.AppendLine("    }");
                    rSb.AppendLine("}");

                    var rFilePath = scriptsPath + rType.Name + ".cs";
                    File.WriteAllText(rFilePath, rSb.ToString());

                    if (bHasCustom)
                    {
                        LogGame.Log($"{rType.Name}  需要检查，部分内容需要手动实现反序列化");
                    }
                }
            }

#endregion

#region CommandFactory

            {
                var rFactoryBuilder = new StringBuilder();
                rFactoryBuilder.AppendLine("using System.Collections.Generic;");
                rFactoryBuilder.AppendLine("using IQIGame.Onigao.Framework.Serialization;");
                rFactoryBuilder.AppendLine("using IQIGame.Onigao.GamePlay;");
                rFactoryBuilder.AppendLine("using IQIGame.Onigao.Framework;");
                rFactoryBuilder.AppendLine("using System;");
                rFactoryBuilder.AppendLine("");
                rFactoryBuilder.AppendLine("namespace IQIGame.Onigao.Logic");
                rFactoryBuilder.AppendLine("{");
                rFactoryBuilder.AppendLine("    public static partial class BattleUpdateFactory");
                rFactoryBuilder.AppendLine("    {");
                // 静态构造函数
                rFactoryBuilder.AppendLine("        static BattleUpdateFactory()");
                rFactoryBuilder.AppendLine("        {");
                rFactoryBuilder.AppendLine("            _commandTypes = new Dictionary<Type, EBattleUpdateType>();");
                for (int i = (int)EBattleUpdateType.Min + 1; i < (int)EBattleUpdateType.Max; i++)
                {
                    var rType = (EBattleUpdateType)i;
                    rFactoryBuilder.AppendLine($"            _commandTypes[typeof(BattleCommand_{rType})] = EBattleUpdateType.{rType};");
                }
                rFactoryBuilder.AppendLine("            if (_commandTypes.Count != (int)EBattleUpdateType.Max - 1)");
                rFactoryBuilder.AppendLine("            {");
                rFactoryBuilder.AppendLine("                LogicLog.LogError(\"BattleUpdateFactory commandTypes is not enough\");");
                rFactoryBuilder.AppendLine("            }");
                rFactoryBuilder.AppendLine("        }");
                // TryParseUpdate
                rFactoryBuilder.AppendLine("        public static object TryParseUpdate(SInputStream rInput)");
                rFactoryBuilder.AppendLine("        {");
                rFactoryBuilder.AppendLine("            ISerializeCustomPOD data = null;");
                rFactoryBuilder.AppendLine("            var rCustomType = (EBattleUpdateType)rInput.Read_byte();");
                rFactoryBuilder.AppendLine("            switch (rCustomType)");
                rFactoryBuilder.AppendLine("            {");
                for (int i = (int)EBattleUpdateType.Min + 1; i < (int)EBattleUpdateType.Max; i++)
                {
                    var rType = (EBattleUpdateType)i;
                    rFactoryBuilder.AppendLine($"            case EBattleUpdateType.{rType}:");
                    rFactoryBuilder.AppendLine($"               data = BaseBattleCommand.Get<BattleCommand_{rType}>();");
                    rFactoryBuilder.AppendLine($"               break;");
                }
                rFactoryBuilder.AppendLine($"            default:");
                rFactoryBuilder.AppendLine("               throw new Exception($\"在尝试解析未指定的BattleCommand:{rCustomType}\");");
                rFactoryBuilder.AppendLine("            }");
                rFactoryBuilder.AppendLine("            data.DeSerialize(rInput);");
                rFactoryBuilder.AppendLine("            return data;");
                rFactoryBuilder.AppendLine("        }");

                rFactoryBuilder.AppendLine("    }");
                rFactoryBuilder.AppendLine("}");
                var rFactoryFilePath = scriptsPath + "BattleUpdateFactory.cs";
                File.WriteAllText(rFactoryFilePath, rFactoryBuilder.ToString());
            }

#endregion

#region CommandView

            {
                var rControllerBuilder = new StringBuilder();
                A(rControllerBuilder, 0, "using System;");
                A(rControllerBuilder, 0, "using IQIGame.Onigao.Framework;");
                A(rControllerBuilder, 0, "using IQIGame.Onigao.Logic;");
                A(rControllerBuilder, 0, "using NetProtocol.POD;");
                A(rControllerBuilder, 0, "");
                A(rControllerBuilder, 0, "namespace IQIGame.Onigao.GamePlay");
                A(rControllerBuilder, 0, "{");
                A(rControllerBuilder, 1, "public partial class BattleRenderQueueController");
                A(rControllerBuilder, 1, "{");
                A(rControllerBuilder, 2, "private bool TryParseUpdate(BattleUpdatePOD rPOD, out IBaseBattleCommandView rCommandView)");
                A(rControllerBuilder, 2, "{");
                A(rControllerBuilder, 3, "rCommandView = null;");
                A(rControllerBuilder, 3, "if (rPOD == null)");
                A(rControllerBuilder, 3, "{");
                A(rControllerBuilder, 4, "return false;");
                A(rControllerBuilder, 3, "}");
                A(rControllerBuilder, 3, "switch ((EBattleUpdateType)rPOD.type)");
                A(rControllerBuilder, 3, "{");
                for (int i = (int)EBattleUpdateType.Min + 1; i < (int)EBattleUpdateType.Max; i++)
                {
                    var rType = (EBattleUpdateType)i;
                    A(rControllerBuilder, 4, $"case EBattleUpdateType.{rType}:");
                    A(rControllerBuilder, 4, "{");
                    A(rControllerBuilder, 5, $"var rCommand = rPOD.data as BattleCommand_{rType};");
                    A(rControllerBuilder, 5, $"var rView = ClassPool.Get<BattleCommandView_{rType}>();");
                    A(rControllerBuilder, 5, "rView.Initialize(rCommand, rPOD.executerId, this._cancel);");
                    A(rControllerBuilder, 5, "rCommandView = rView;");
                    A(rControllerBuilder, 5, "break;");
                    A(rControllerBuilder, 4, "}");
                }
                A(rControllerBuilder, 4, "default:");
                A(rControllerBuilder, 5, "throw new Exception($\"在尝试解析未指定的BattleCommand:{(EBattleUpdateType)rPOD.type}\");");
                A(rControllerBuilder, 3, "}");
                A(rControllerBuilder, 3, "return rCommandView != null;");
                A(rControllerBuilder, 2, "}");
                A(rControllerBuilder, 1, "}");
                A(rControllerBuilder, 0, "}");
                File.WriteAllText(queueControllerPath, rControllerBuilder.ToString());
            }
#endregion

            AssetDatabase.Refresh();
            LogGame.Log("生成完成");
        }

        /// <summary>
        /// Append
        /// </summary>
        static void A(StringBuilder sb, int indentCount, string value)
        {
            for (int i = 0; i < indentCount; i++)
            {
                sb.Append(tabStr);
            }
            sb.Append(value);
            sb.Append('\n');
        }

        private static bool AppendField(FieldInfo rField, ref StringBuilder rSb, bool bSerialize, out bool bHasCustom)
        {
            var rFieldType = rField.FieldType;
            bHasCustom = false;
            if (rFieldType == typeof(int))
            {
                if (bSerialize)
                {
                    rSb.AppendLine($"            _buf.Write_int(this.{rField.Name});");
                }
                else
                {
                    rSb.AppendLine($"            this.{rField.Name} = _buf.Read_int();");
                }
            }
            else if (rFieldType == typeof(long))
            {
                if (bSerialize)
                {
                    rSb.AppendLine($"            _buf.Write_long(this.{rField.Name});");
                }
                else
                {
                    rSb.AppendLine($"            this.{rField.Name} = _buf.Read_long();");
                }
            }
            else if (rFieldType == typeof(string))
            {
                if (bSerialize)
                {
                    rSb.AppendLine($"            _buf.Write_string(this.{rField.Name});");
                }
                else
                {
                    rSb.AppendLine($"            this.{rField.Name} = _buf.Read_string();");
                }
            }
            else if (rFieldType == typeof(bool))
            {
                if (bSerialize)
                {
                    rSb.AppendLine($"            _buf.Write_boolean(this.{rField.Name});");
                }
                else
                {
                    rSb.AppendLine($"            this.{rField.Name} = _buf.Read_boolean();");
                }
            }
            else if (rFieldType == typeof(List<int>))
            {
                if (bSerialize)
                {
                    rSb.AppendLine($"            SerializeCustomPODUtil.SerializeListInt(_buf, this.{rField.Name});");
                }
                else
                {
                    rSb.AppendLine($"            SerializeCustomPODUtil.DeSerializeListInt(_buf, ref this.{rField.Name});");
                }
            }
            else if (rFieldType == typeof(byte[]))
            {
                if (bSerialize)
                {
                    rSb.AppendLine($"            _buf.Write_bytes(this.{rField.Name});");
                }
                else
                {
                    rSb.AppendLine($"            this.{rField.Name} = _buf.Read_bytes();");
                }
            }
            else if (rFieldType.IsGenericType && rFieldType.GenericTypeArguments.Length > 0 && rFieldType.GenericTypeArguments[0].GetInterfaces().Contains(typeof(ISerializeCustomPOD)))
            {
                if (bSerialize)
                {
                    rSb.AppendLine($"            SerializeCustomPODUtil.SerializeList(_buf, this.{rField.Name});");
                }
                else
                {
                    rSb.AppendLine($"            SerializeCustomPODUtil.DeSerializeList(_buf, ref this.{rField.Name});");
                }
            }
            else if (rFieldType.GetInterfaces().Contains(typeof(ISerializeCustomPOD)) && rFieldType != typeof(ISerializeCustomPOD))
            {
                if (bSerialize)
                {
                    rSb.AppendLine($"            SerializeCustomPODUtil.SerializeObject(_buf, this.{rField.Name});");
                }
                else
                {
                    rSb.AppendLine($"            SerializeCustomPODUtil.DeSerializeObject(_buf, ref this.{rField.Name});");
                }
            }
            else if (rFieldType.GetInterfaces().Contains(typeof(IPOD)) && rFieldType != typeof(IPOD))
            {
                if (bSerialize)
                {
                    rSb.AppendLine($"            SerializeCustomPODUtil.SerializePOD(_buf, this.{rField.Name});");
                }
                else
                {
                    rSb.AppendLine($"            SerializeCustomPODUtil.DeSerializePOD(_buf, ref this.{rField.Name});");
                }
            }
            // 下面是特殊处理
            else if (rFieldType == typeof(List<int>[]))
            {
                if (bSerialize)
                {
                    rSb.AppendLine($"            _buf.Write_boolean(this.{rField.Name} != null);");
                    rSb.AppendLine($"            if (this.{rField.Name} != null)");
                    rSb.AppendLine("            {");
                    rSb.AppendLine($"               _buf.Write_int(this.{rField.Name}.Length);");
                    rSb.AppendLine($"               for (int i = 0; i < this.{rField.Name}.Length; i++)");
                    rSb.AppendLine("               {");
                    rSb.AppendLine($"                   SerializeCustomPODUtil.SerializeListInt(_buf, this.{rField.Name}[i]);");
                    rSb.AppendLine("               }");
                    rSb.AppendLine("            }");
                }
                else
                {
                    rSb.AppendLine($"            var bNotNull = _buf.Read_boolean();");
                    rSb.AppendLine($"            if (bNotNull)");
                    rSb.AppendLine("            {");
                    rSb.AppendLine($"               this.{rField.Name} = new List<int>[_buf.Read_int()];");
                    rSb.AppendLine($"               for (int i = 0; i < this.{rField.Name}.Length; i++)");
                    rSb.AppendLine("               {");
                    rSb.AppendLine($"                   SerializeCustomPODUtil.DeSerializeListInt(_buf, ref this.{rField.Name}[i]);");
                    rSb.AppendLine("               }");
                    rSb.AppendLine("            }");
                }
            }
            else if (rFieldType == typeof(ISerializeCustomPOD))
            {
                if (bSerialize)
                {
                    rSb.AppendLine($"            SerializeCustomPODUtil.SerializeObject(_buf, this.{rField.Name});");
                }
                else
                {
                    rSb.AppendLine($"            //{rField.Name} 需要手动实现反序列化");
                    bHasCustom = true;
                }
            }
            else if (rFieldType == typeof(TAny))
            {
                if (bSerialize)
                {
                    rSb.AppendLine($"            this.{rField.Name}.Serialize(_buf);");
                }
                else
                {
                    rSb.AppendLine($"            //{rField.Name} 需要手动实现反序列化");
                    bHasCustom = true;
                }
            }
            else
            {
                return false;
            }

            return true;
        }

        /// <summary>
        /// 把需要手动实现反序列化的结构放在后面
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        private static int FieldSort(FieldInfo x, FieldInfo y)
        {
            var xx = x.FieldType == typeof(ISerializeCustomPOD) || x.FieldType == typeof(TAny);
            var yy = y.FieldType == typeof(ISerializeCustomPOD) || x.FieldType == typeof(TAny);
            return xx.CompareTo(yy);
        }
    }
}